/*
 * \brief  Paging-server framework
 * \author Norman Feske
 * \author Christian Helmuth
 * \date   2006-04-28
 */

/*
 * Copyright (C) 2006-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _INCLUDE__BASE__PAGER_H_
#define _INCLUDE__BASE__PAGER_H_

#include <base/thread.h>
#include <base/errno.h>
#include <base/ipc_pager.h>
#include <base/printf.h>
#include <base/object_pool.h>
#include <cap_session/cap_session.h>

namespace Genode {

	/**
	 * Special server object for paging
	 *
	 * A 'Pager_object' is very similar to a 'Server_object'. It is just a
	 * special implementation for page-fault handling, which does not allow to
	 * define a "badge" for pager capabilities.
	 */
	class Pager_object : public Object_pool<Pager_object>::Entry
	{
		protected:

			unsigned long _badge;  /* local name for this pager object */

		public:

			Pager_object(unsigned long badge) : _badge(badge) { }
			virtual ~Pager_object() { }

			unsigned long badge() const { return _badge; }

			/**
			 * Interface to be implemented by a derived class
			 *
			 * \param ps  'Ipc_pager' stream
			 *
			 * Returns !0 on error and pagefault will not be answered.
			 */
			virtual int pager(Ipc_pager &ps) = 0;
	};


	/**
	 * A 'Pager_activation' processes one page fault of a 'Pager_object' at a time.
	 */
	class Pager_entrypoint;
	class Pager_activation_base: public Thread_base
	{
		private:

			Capability        _cap;
			Pager_entrypoint *_ep;       /* entry point to which the
			                                activation belongs */

			volatile bool     _cap_valid;

		public:

			Pager_activation_base() : _cap(Capability()), _ep(0), _cap_valid(0) { }

			/**
			 * Set entry point, which the activation serves
			 *
			 * This function must by called by a 'Server_entrypoint'
			 * on add_activation() only.
			 */
			void ep(Pager_entrypoint *ep) { _ep = ep; }

			/**
			 * Thread interface
			 */
			void entry();

			/**
			 * Return capability to this activation
			 *
			 * This function should only be called from 'Server_entrypoint'
			 */
			Capability cap()
			{
				/* ensure that the initialization of our Ipc_pager is done */
				while (!_cap_valid);
				return _cap;
			}
	};


	/**
	 * Paging entry point
	 *
	 * For a paging entry point can hold only one activation. So, paging is
	 * strictly serialized for one entry point.
	 */
	class Pager_entrypoint : public Object_pool<Pager_object>
	{
		private:

			Pager_activation_base *_activation;
			Cap_session           *_cap_session;

		public:

			/**
			 * Constructor
			 *
			 * \param cap_session  Cap_session for creating capabilities
			 *                     for the pager objects managed by this
			 *                     entry point
			 * \param a            initial activation
			 */
			Pager_entrypoint(Pager_activation_base *a = 0);

			/**
			 * Add activation to activation pool of this entry point
			 */
			int add_activation(Pager_activation_base *t);

			/**
			 * Associate Pager_object with the entry point
			 */
			Capability manage(Pager_object *obj);

			/**
			 * Dissolve Pager_object from entry point
			 */
			void dissolve(Pager_object *obj);
	};


	template <int STACK_SIZE>
	class Pager_activation : public Pager_activation_base
	{
		private:

			/*
			 * The '_align' member is a dummy to force
			 * the alignment of the consecutive variables.
			 */
			long _align;

			char _stack[STACK_SIZE];

		public:

			Pager_activation() { _start(&_stack[STACK_SIZE - sizeof(umword_t)], "pager"); }
	};
}

#endif /* _INCLUDE__BASE__PAGER_H_ */
